/*
 * BSM6.0
 *
 * Copyright 2012-2013 (C) SINODATA CO., LTD. All Rights Reserved.
 */
package com.sinodata.bsm.center.service.topo;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.sinodata.bsm.center.cache.EventTypeCache;
import com.sinodata.bsm.center.cache.PropertyCache;
import com.sinodata.bsm.center.cache.RelationTypeCache;
import com.sinodata.bsm.center.cache.ResCache;
import com.sinodata.bsm.center.cache.ResTypeCache;
import com.sinodata.bsm.center.cache.ResTypeTooltipCache;
import com.sinodata.bsm.center.cache.TopuConfCache;
import com.sinodata.bsm.center.cache.TopuPlayOrderCache;
import com.sinodata.bsm.center.dao.impl.EventDaoImpl;
import com.sinodata.bsm.center.dao.impl.TopoDaoImpl;
import com.sinodata.bsm.center.service.event.EventCorrelationService;
import com.sinodata.bsm.center.service.event.EventService;
import com.sinodata.bsm.center.service.performance.RealTimeService;
import com.sinodata.bsm.common.constants.EventConstants;
import com.sinodata.bsm.common.constants.ResConstants;
import com.sinodata.bsm.common.constants.TopoConstants;
import com.sinodata.bsm.common.vo.Event;
import com.sinodata.bsm.common.vo.EventCorrelation;
import com.sinodata.bsm.common.vo.EventType;
import com.sinodata.bsm.common.vo.Property;
import com.sinodata.bsm.common.vo.RealTimeViewConf;
import com.sinodata.bsm.common.vo.RelationType;
import com.sinodata.bsm.common.vo.Res;
import com.sinodata.bsm.common.vo.ResType;
import com.sinodata.bsm.common.vo.ResTypeTooltip;
import com.sinodata.bsm.common.vo.TopuCatalog;
import com.sinodata.bsm.common.vo.TopuConf;
import com.sinodata.bsm.common.vo.TopuPlayOrder;

/**
 * <p>
 * Description: 
 * </p>
 *
 * @author sunxiangxue
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-5-10 下午4:34:04          sunxiangxue        1.0         To create
 * </p>
 *
 * @since 
 * @see     
 */
@Service
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class TopoService {

    Logger logger = Logger.getLogger(TopoService.class);

    @Autowired
    private TopoDaoImpl topoDaoImpl;

    @Autowired
    private TopuConfCache topuConfCache;//拓扑缓存对象

    @Autowired
    private ResCache resCache;

    @Autowired
    private EventTypeCache eventTypeCache;

    @Autowired
    private RelationTypeCache relationTypeCache;

    @Autowired
    private PropertyCache propertyCache;

    @Autowired
    private ResTypeCache resTypeCache;

    @Autowired
    private ResTypeTooltipCache resTypeTooltipCache;

    @Autowired
    private EventService eventService;

    @Autowired
    private TopoCatalogService topoCatalogService;

    @Autowired
    private TopuPlayOrderCache topuPlayOrderCache;

    @Autowired
    private EventCorrelationService eclService;

    @Autowired
    private EventDaoImpl eventDao;

    @Autowired
    private RealTimeService realTimeService;

    /**
     * 查询所有拓扑图信息。
     * @return 拓扑图集合
     */
    public List<TopuConf> findAll() {
        return topuConfCache.findAll();
    }

    /**
     * 根据拓扑分类ID查询拓扑集合
     * @param catalogId 拓扑分类ID
     * @return 拓扑集合
     */
    public List<TopuConf> findByCatalogId(Long catalogId) {
        if (catalogId == null)
            return new ArrayList<TopuConf>();
        return topuConfCache.findByCatalogId(catalogId);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void saveOrUpdate(TopuConf topuConf) throws Exception {
        topoDaoImpl.saveOrUpdate(topuConf);

    }

    public TopuConf findById(Long id) {
        return topuConfCache.get(id);
    }

    /**
     * 根据ID删除拓扑图
     * @param id
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void delete(Long id) {
        TopuConf topuConf = topuConfCache.get(id);
        topoDaoImpl.delete(topuConf);
        topoDaoImpl.deleteTopoPlayOrderByTopoId(id);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteTopuPlayOrderByUserId(String userId) {
        topoDaoImpl.deleteTopuPlayByUserId(userId);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void saveTopuPlayOrder(List<TopuPlayOrder> list) throws Exception {
        topoDaoImpl.batchSave(list);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteByCatalogId(TopuConf topuConf) {
        delete(topuConf.getId());
        topuPlayOrderCache.removeByTopoId(topuConf.getId());
    }

    /**
     * 查询拓扑图中资源状态信息
     * @param resourceIds
     * @return
     */
    public JSONArray findTopoResourceStatus(List<Long> resourceIds) {
        JSONArray jsonArray = new JSONArray();
        Res res = null;
        for (Long id : resourceIds) {
            res = resCache.get(id);
            JSONObject jsonObject = new JSONObject();
            if (res != null) {
                jsonObject.element("id", res.getId());
                jsonObject.element("healthStatus", res.getHealthStatus());
                jsonObject.element("paused", res.getPaused());
                int eventCount = eventService.getNewEventsCount(id);
                jsonObject.element("eventCount", eventCount);
            } else {//被删除的资源，需要展现为一个特定状态
                jsonObject.element("id", id);
                jsonObject.element("healthStatus", TopoConstants.RES_DELETED);
                jsonObject.element("paused", ResConstants.RES_NOT_PAUSED);
                jsonObject.element("eventCount", 0);
            }
            jsonArray.add(jsonObject);
        }

        return jsonArray;
    }

    /**
     * @return
     */
    public List<RelationType> findAllRelationType() {
        return relationTypeCache.getAll();
    }

    /**
     * @param resourceId
     * @return
     */
    public List<Property> findNormByResourceId(long resourceId) {
        List<Property> list = new ArrayList<Property>();
        List<Property> tempList = propertyCache.getByResId(resourceId);
        if (tempList != null)
            list.addAll(tempList);
        Res res = resCache.get(resourceId);
        if (res != null) {
            tempList = propertyCache.getByResTypeId(res.getResTypeId());
            if (tempList != null)
                list.addAll(tempList);
        }
        return list;
    }

    /**
     * @return
     */
    public List<ResType> findAllResourceType() {
        return resTypeCache.getAll();
    }

    /**
     * @return
     */
    public List<Property> findAllProperty() {
        return propertyCache.getAll();
    }

    /**
     * @param resourceTypeId
     * @return
     */
    public ResTypeTooltip findToolTipInfoByRelationId(long resourceTypeId) {
        return resTypeTooltipCache.get(resourceTypeId);
    }

    public Res findResByResId(long resourceId) {
        return resCache.get(resourceId);
    }

    public List<TopuConf> findTopoByResId(long resId) {
        return topuConfCache.findByResId(resId);
    }

    /**
     * 通过资源ID查询该资源和其子资源事件集合。
     * @param resourceIds
     * @return
     */
    public JSONArray findResEventsByResId(Long[] resourceIds) {
        List<Event> list = eventService.getNewEvents(resourceIds);
        Res res = null;
        JSONArray jsonArray = new JSONArray();
        JSONObject jsonObject = null;
        EventType eventType = null;
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (Event event : list) {
            res = resCache.get(event.getResId());
            eventType = eventTypeCache.get(event.getEventTypeId());
            jsonObject = new JSONObject();
            jsonObject.element("resourceName", res.getName());
            jsonObject.element("eventId", event.getId());
            jsonObject.element("eventLevel", event.getLevel());//事件级别
            jsonObject.element("eventLevelDesc", EventConstants.getLevelDesc(event.getLevel()));//事件级别描述
            jsonObject.element("eventType", eventType.getName());//事件类别
            jsonObject.element("eventStatus", EventConstants.getStatusDesc(event.getStatus()));
            jsonObject.element("desc", event.getMsg());
            jsonObject.element("createDate", df.format(event.getOccurTime()));
            jsonArray.add(jsonObject);
        }
        return jsonArray;
    }

    /**
     * 查询首页播放的拓扑集合
     * @return
     */
    public JSONArray findShowTopos() {
        JSONArray jSONArray = new JSONArray();
        JSONObject jsonObject = null;
        //播放的拓扑图
        for (TopuConf topuConf : topoDaoImpl.findShowTopos()) {
            jsonObject = new JSONObject();
            jsonObject.element("id", topuConf.getId());
            jsonObject.element("name", topuConf.getName());
            jsonObject.element("xml", topuConf.getXml());
            jsonObject.element("type", "0");//拓扑图
            jSONArray.add(jsonObject);
        }
        //播放的性能图
        List<TopuPlayOrder> playList = topuPlayOrderCache.getAll();
        for (RealTimeViewConf realTimeViewConf : realTimeService.findAllFreeCustomView()) {
            Long id = realTimeViewConf.getId();
            Boolean canPlay = false;
            //是否在播放列表
            for (TopuPlayOrder topuPlayOrder : playList) {
                if (id.equals(topuPlayOrder.getTopuConfId())) {
                    canPlay = true;
                    break;
                }
            }
            if (!canPlay)
                continue;
            jsonObject = new JSONObject();
            jsonObject.element("id", id);
            jsonObject.element("name", realTimeViewConf.customName());
            jsonObject.element("xml", realTimeViewConf.getXml());
            jsonObject.element("type", "1");//性能图
            jSONArray.add(jsonObject);
        }
        return jSONArray;
    }

    /**
     * 初始化拓扑树
     * @param topoIdList 可获取的拓扑ID集合
     * @param canManageTopo 是否可编辑拓扑图
     * @return
     */
    public JSONArray initTopoTree(List<Long> topoIdList, boolean canManageTopo) {
        JSONArray jsonArray = new JSONArray();
        List<TopuCatalog> topoCatalogList = topoCatalogService.findAll();
        logger.debug("size of topo catalog:" + topoCatalogList.size());
        JSONObject jsonObject = null;
        List<TopuConf> topoList = null;
        JSONArray jsonArrayChild = null;
        for (TopuCatalog topuCatalog : topoCatalogList) {
            Long catalogId = topuCatalog.getId();
            jsonObject = new JSONObject();
            jsonObject.element("id", catalogId);
            jsonObject.element("name", topuCatalog.getName());
            jsonObject.element("pId", topuCatalog.getParent());
            jsonObject.element("topoId", "");
            topoList = findByCatalogId(catalogId);
            jsonArrayChild = new JSONArray();
            JSONObject jsonObjectIn = null;
            for (TopuConf topuConf : topoList) {
                //如果没有拓扑编辑权限且不在该角色可见范围中，那么不包装该节点数据到JSON
                if (!canManageTopo && !topoIdList.contains(topuConf.getId()))
                    continue;
                jsonObjectIn = new JSONObject();
                jsonObjectIn.element("id", topuConf.getId());
                jsonObjectIn.element("name", topuConf.getName());
                jsonObjectIn.element("topoId", topuConf.getId());
                jsonArrayChild.add(jsonObjectIn);
            }
            jsonObject.element("children", jsonArrayChild);
            //如果没有编辑拓扑的权限且目录为空，则不包装该目录数据到JSON
            if (!canManageTopo && jsonArrayChild.size() == 0)
                continue;
            jsonArray.add(jsonObject);
        }
        return jsonArray;
    }

    /**
     * 通过主事件ID查询所有关联事件。
     * @param mainEventId
     * @return
     */
    public JSONArray findByMainEvent(Long mainEventId) {
        List<EventCorrelation> list = eclService.findByMainEvent(mainEventId);
        JSONArray jsonArray = new JSONArray();
        JSONObject jsonObject = null;
        Event event = null;
        for (EventCorrelation eventCorrelation : list) {
            jsonObject = new JSONObject();
            jsonObject.element("eventId", eventCorrelation.getEventId());
            jsonObject.element("mainEventId", eventCorrelation.getMainEventId());
            event = (Event) eventDao.findById(Event.class, eventCorrelation.getEventId());
            jsonObject.element("msg", event.getMsg());
            jsonObject.element("eventType", eventTypeCache.get(event.getEventTypeId()).getName());
            jsonArray.add(jsonObject);
        }
        //增加根节点数据
        jsonObject = new JSONObject();
        jsonObject.element("eventId", mainEventId);
        event = (Event) eventDao.findById(Event.class, mainEventId);
        jsonObject.element("msg", event.getMsg());
        jsonObject.element("eventType", eventTypeCache.get(event.getEventTypeId()).getName());
        jsonArray.add(jsonObject);
        return jsonArray;
    }
}
